﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Doodleberg
{
    class ControlManager
    {
        private ControlAction[] controls;

        public const int DRAW = 1;
        public const int TOGGLERUN = 2;
        public const int LEVELSKIP = 3;
        public const int ADVANCELEVEL = 4;
        public const int STRAIGHTLINE = 5;
        public const int DELETE = 6;
        public const int EDITOR_CHANGE = 7;
        public const int EDITOR_LOAD = 8;
        public const int EDITOR_SAVE = 9;

        public const int controlMax = 9;

        private KeyboardState lastKeyboardState;
        private MouseState lastMouseState;
        private GamePadState lastPadState;

        //Constructor sets up data structures
        public ControlManager()
        {
            controls = new ControlAction[controlMax + 1];

            lastKeyboardState = Keyboard.GetState();
            lastMouseState = Mouse.GetState();
            lastPadState = GamePad.GetState(PlayerIndex.One);

            controls[DRAW] = new ControlAction();
            controls[DRAW].setHold(true);
            controls[DRAW].addLeftMouse();

            controls[TOGGLERUN] = new ControlAction();
            controls[TOGGLERUN].setHold(false);
            controls[TOGGLERUN].addKeyPress(Keys.Space);

            controls[LEVELSKIP] = new ControlAction();
            controls[LEVELSKIP].setHold(false);
            controls[LEVELSKIP].addKeyPress(Keys.T);

            controls[ADVANCELEVEL] = new ControlAction();
            controls[ADVANCELEVEL].setHold(false);
            controls[ADVANCELEVEL].addKeyPress(Keys.Enter);

            controls[STRAIGHTLINE] = new ControlAction();
            controls[STRAIGHTLINE].setHold(true);
            controls[STRAIGHTLINE].addKeyPress(Keys.LeftShift);
            controls[STRAIGHTLINE].addKeyPress(Keys.RightShift);

            controls[DELETE] = new ControlAction();
            controls[DELETE].setHold(false);
            controls[DELETE].addRightMouse();

            controls[EDITOR_CHANGE] = new ControlAction();
            controls[EDITOR_CHANGE].setHold(false);
            controls[EDITOR_CHANGE].addKeyPress(Keys.LeftControl);
            controls[EDITOR_CHANGE].addKeyPress(Keys.RightControl);

            controls[EDITOR_LOAD] = new ControlAction();
            controls[EDITOR_LOAD].setHold(false);
            controls[EDITOR_LOAD].addKeyPress(Keys.O);

            controls[EDITOR_SAVE] = new ControlAction();
            controls[EDITOR_SAVE].setHold(false);
            controls[EDITOR_SAVE].addKeyPress(Keys.S);
        }


        //Self-explanatory
        public void update(GameTime gameTime)
        {
            KeyboardState keyboardState = Keyboard.GetState();
            MouseState mouseState = Mouse.GetState();
            GamePadState padState = GamePad.GetState(PlayerIndex.One);

            foreach (ControlAction con in controls)
            {
                
                if (con != null)
                {
                    con.value = false;
                    if (con.result(keyboardState, mouseState, padState))
                    {
                        if (con.hold)
                        {
                            con.value = true;
                        }
                        else
                        {
                            if (!con.result(lastKeyboardState, lastMouseState, lastPadState))
                                con.value = true;
                            else
                                con.value = false;
                        }
                    }
                }
            }

            lastKeyboardState = keyboardState;
            lastMouseState = mouseState;
            lastPadState = padState;
        }


        //Get the state of a control
        public bool getControl(int controlConst)
        {
            return controls[controlConst].value;
        }


        //Reset controls
        public void clearControls()
        {
            foreach (ControlAction c in controls)
            {
                if (c != null)
                    c.value = false;
            }
        }
    }


    //Describes one action and the different controls that can activate it
    class ControlAction
    {
        private List<Keys> keyPress;
        private List<Buttons> buttonPress;
        private bool leftmouse;
        private bool rightmouse;
        private bool middlemouse;
        public bool hold { get; private set; }
        public bool value;

        public ControlAction()
        {
            keyPress = new List<Keys>();
            buttonPress = new List<Buttons>();
        }

        //Are any of the buttons pressed?
        //Doesn't account for Hold
        public bool result(KeyboardState kstate, MouseState mstate, GamePadState pstate)
        {
            foreach (Keys k in keyPress)
            {
                if (kstate.IsKeyDown(k))
                    return true;
            }
            foreach (Buttons b in buttonPress)
            {
                if (pstate.IsButtonDown(b))
                    return true;
            }
            if (mstate.LeftButton == ButtonState.Pressed && leftmouse)
                return true;
            if (mstate.RightButton == ButtonState.Pressed && rightmouse)
                return true;
            if (mstate.MiddleButton == ButtonState.Pressed && middlemouse)
                return true;

            return false;
        }

        //Does button continue to act when held down?
        public void setHold(bool hold)
        {
            this.hold = hold;
        }

        public void addPadButton(Buttons but)
        {
            buttonPress.Add(but);
        }

        public void addKeyPress(Keys key)
        {
            keyPress.Add(key);
        }

        public void addLeftMouse()
        {
            leftmouse = true;
        }

        public void addRightMouse()
        {
            rightmouse = true;
        }

        public void addMiddleMouse()
        {
            middlemouse = true;
        }

        public void clear()
        {
            keyPress.Clear();
            buttonPress.Clear();
            leftmouse = false;
            rightmouse = false;
            middlemouse = false;
        }
    }
}
